﻿using System;
using System.Collections.Generic;

namespace NetTopologySuite.GeometriesGraph.Index
{
	public class SimpleMCSweepLineIntersector : EdgeSetIntersector
	{
		public override void ComputeIntersections(IList<Edge> edges, SegmentIntersector si, bool testAllSegments)
		{
			if (testAllSegments)
			{
				this.Add(edges, null);
			}
			else
			{
				this.Add(edges);
			}
			this.ComputeIntersections(si);
		}

		public override void ComputeIntersections(IList<Edge> edges0, IList<Edge> edges1, SegmentIntersector si)
		{
			this.Add(edges0, edges0);
			this.Add(edges1, edges1);
			this.ComputeIntersections(si);
		}

		private void Add(IEnumerable<Edge> edges)
		{
			foreach (Edge edge in edges)
			{
				this.Add(edge, edge);
			}
		}

		private void Add(IEnumerable<Edge> edges, object edgeSet)
		{
			foreach (Edge edge in edges)
			{
				this.Add(edge, edgeSet);
			}
		}

		private void Add(Edge edge, object edgeSet)
		{
			MonotoneChainEdge monotoneChainEdge = edge.MonotoneChainEdge;
			int[] startIndexes = monotoneChainEdge.StartIndexes;
			for (int i = 0; i < startIndexes.Length - 1; i++)
			{
				MonotoneChain obj = new MonotoneChain(monotoneChainEdge, i);
				SweepLineEvent sweepLineEvent = new SweepLineEvent(edgeSet, monotoneChainEdge.GetMinX(i), obj);
				this._events.Add(sweepLineEvent);
				this._events.Add(new SweepLineEvent(monotoneChainEdge.GetMaxX(i), sweepLineEvent));
			}
		}

		private void PrepareEvents()
		{
			this._events.Sort();
			for (int i = 0; i < this._events.Count; i++)
			{
				SweepLineEvent sweepLineEvent = this._events[i];
				if (sweepLineEvent.IsDelete)
				{
					sweepLineEvent.InsertEvent.DeleteEventIndex = i;
				}
			}
		}

		private void ComputeIntersections(SegmentIntersector si)
		{
			this._nOverlaps = 0;
			this.PrepareEvents();
			for (int i = 0; i < this._events.Count; i++)
			{
				SweepLineEvent sweepLineEvent = this._events[i];
				if (sweepLineEvent.IsInsert)
				{
					this.ProcessOverlaps(i, sweepLineEvent.DeleteEventIndex, sweepLineEvent, si);
				}
			}
		}

		private void ProcessOverlaps(int start, int end, SweepLineEvent ev0, SegmentIntersector si)
		{
			MonotoneChain monotoneChain = (MonotoneChain)ev0.Object;
			for (int i = start; i < end; i++)
			{
				SweepLineEvent sweepLineEvent = this._events[i];
				if (sweepLineEvent.IsInsert)
				{
					MonotoneChain mc = (MonotoneChain)sweepLineEvent.Object;
					if (!ev0.IsSameLabel(sweepLineEvent))
					{
						monotoneChain.ComputeIntersections(mc, si);
						this._nOverlaps++;
					}
				}
			}
		}

		private readonly List<SweepLineEvent> _events = new List<SweepLineEvent>();

		private int _nOverlaps;
	}
}
